package com.emser.unc.client.presenter;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;

import com.emser.unc.client.CloudMobile;
import com.emser.unc.client.event.AddCustomerEvent;
import com.emser.unc.client.event.EditCustomerEvent;
import com.emser.unc.client.helper.RPCCall;
import com.emser.unc.client.service.CustomerService;
import com.emser.unc.client.service.CustomerServiceAsync;
import com.emser.unc.serializable.CustomerDTO;
import com.emser.unc.serializable.ResultDTO;
import com.emser.unc.serializable.UserAccountDTO;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.SimpleEventBus;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.RangeChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent;

public class CustomersPresenter implements Presenter {
	private Display display;
	private SimpleEventBus eventBus;
	private CustomerServiceAsync rpcCustomerService;
	private UserAccountDTO userA;
	private ArrayList<Long> customerIds;
	private ArrayList<String> searchParam;
	private boolean search = false;
	private int pageSize = CloudMobile.constants.pageSizeCP();
	private ArrayList<String> cursors = new ArrayList<String>();
	private int pageNum;
	private String pageCursor;
	
	public interface Display {	
	    Widget asWidget();
	    HasClickHandlers getSearchButton();
	    HasClickHandlers getAddButton();
	    HasClickHandlers getRemoveButton();
	    HasClickHandlers getBtnPopUpDCancel();
	    HasClickHandlers getBtnPopUpDDelete();
	    MultiSelectionModel<CustomerDTO> getSelectionModel();
		HasData<CustomerDTO> getTable();
		HasValue<String> getSearchParam();
		Column<CustomerDTO, String> getEditColumn();
		void enableDelete(boolean enabled);
		void enableBtnAdd(boolean enabled);
		void enableBtnPopUpDelete(boolean enabled);
		void enableBtnSearch(boolean enabled);
		void showWarning();
		void disableWarning();
		void showBusyIndicator();
		void hideBusyIndicator();
		void setPage(int page);
		int getPage();
	  }
	
	public CustomersPresenter(UserAccountDTO user,SimpleEventBus eventBus, Display display){
		this.display = display;
		this.eventBus = eventBus;
		this.userA = user;
		this.display.enableDelete(false);
		this.rpcCustomerService = GWT.create(CustomerService.class);
		cursors.add(null);
		bind();
		updateRowCount();
	}
	
	private void bind() {
		this.display.getSearchButton().addClickHandler(new ClickHandler() {   
			public void onClick(ClickEvent event) {
				display.enableBtnSearch(false);
				   handleSearchEvent();
		      }
		});
		this.display.getAddButton().addClickHandler(new ClickHandler() {   
		      public void onClick(ClickEvent event) {
		    	  display.enableBtnSearch(false);
		    	  eventBus.fireEvent(new AddCustomerEvent(rpcCustomerService));
		    	  display.enableBtnSearch(true);
		      }
		});
		this.display.getRemoveButton().addClickHandler(new ClickHandler() {   
		      public void onClick(ClickEvent event) {
		    	  if(!display.getSelectionModel().getSelectedSet().isEmpty()){
		    		  display.enableDelete(false);
		    		  display.showWarning();
		    	  }
		      }
		});
		this.display.getEditColumn().setFieldUpdater(new FieldUpdater<CustomerDTO, String>() {
		      @Override
		      public void update(int index, CustomerDTO object, String value) {
		    		  eventBus.fireEvent(new EditCustomerEvent(object,rpcCustomerService));  
		      }
		});
		this.display.getTable().addRangeChangeHandler(new RangeChangeEvent.Handler() {
	        @Override
	        public void onRangeChange(RangeChangeEvent event) {
	        	doChangeRange();
	    }});
		
		this.display.getBtnPopUpDDelete().addClickHandler(new ClickHandler() {   
		      public void onClick(ClickEvent event) {
		    	  display.enableBtnPopUpDelete(false);
		    	  display.disableWarning();
		    	  doRemove();
		    	  display.enableBtnPopUpDelete(true);
		      }
		});
		this.display.getBtnPopUpDCancel().addClickHandler(new ClickHandler() {   
		      public void onClick(ClickEvent event) {
		    	  display.disableWarning();
		    	  display.enableDelete(true);
		      }
		});
		
		this.display.getSelectionModel().addSelectionChangeHandler(new SelectionChangeEvent.Handler() {  
			public void onSelectionChange(SelectionChangeEvent event) {
				if(display.getSelectionModel().getSelectedSet().isEmpty())
					display.enableDelete(false);
				else
					display.enableDelete(true);
		    }
		});  
	}
	
	private void doRemove() {
		final Set<CustomerDTO> customers = this.display.getSelectionModel().getSelectedSet();
		Iterator<CustomerDTO> iterator= customers.iterator();
		customerIds = new ArrayList<Long>();
		if(customers.isEmpty())
			return;
		else{			
			display.showBusyIndicator();
			while(iterator.hasNext()){
				customerIds.add(iterator.next().getCode());
			}
			new RPCCall<Boolean>(){
				@Override
				public void onFailure(Throwable caught) {
					display.hideBusyIndicator();	
					Window.alert(CloudMobile.constants.eDelete());
					display.enableDelete(true);
				}
				@Override
				public void onSuccess(Boolean result) {
					display.hideBusyIndicator();
					if(result){
						cursors.clear();
						cursors.add(null);
						display.getSelectionModel().clear();
						display.setPage(0);
						search = false;
						updateRowCount();
						display.enableDelete(true);
					}else
					{
						Window.alert(CloudMobile.constants.eServerDelete());
						display.enableDelete(true);
					}
				}
				@Override
				protected void callService(AsyncCallback<Boolean> cb) {
					rpcCustomerService.deleteCustomers(userA.getName(),customerIds,cb);			
				}
			}.retry(3);	
			}
	}
	private void handleSearchEvent(){
		String line,word,subword;
		String [] elementos,subelementos;
		line = display.getSearchParam().getValue();
		if(!line.isEmpty()){			
			searchParam = new ArrayList<String>();
			searchParam.add(userA.getName());
			elementos = line.split("\\s+");
			for(int j=0;j<elementos.length;j++){
				word = elementos[j];
				subelementos = word.split(",");
				for(int i = 0;i<subelementos.length;i++){
					subword = subelementos[i];
					searchParam.add(subword);
				}
			}
			
			if(searchParam.size()< 5){
				search = true;
				cursors.clear();
				cursors.add(null);
				pageCursor = null;
				display.setPage(0);
				updateSRowCount();
			}
		}
		else{
			display.enableBtnSearch(true);
		}
	}
	private void doSearch() {			
		final int start = display.getTable().getVisibleRange().getStart();;
		display.showBusyIndicator();
		pageNum = display.getPage();
		try{
			pageCursor = cursors.get(pageNum);
		}
		catch(Exception e){
			pageCursor = null;
		}
		new RPCCall<ResultDTO<CustomerDTO>>(){
			@Override
			public void onFailure(Throwable caught) {
				display.hideBusyIndicator();
				Window.alert(CloudMobile.constants.eSearchCustomers());
				display.enableBtnSearch(true);
			}
			@Override
			public void onSuccess(ResultDTO<CustomerDTO> result) {
				display.hideBusyIndicator();
				try{
					pageCursor = cursors.get(pageNum+1);
				}
				catch(Exception e){
					pageCursor = null;
				}
				if(result != null){
						if(pageCursor == null)
							cursors.add(result.getCursorString());
						display.getTable().setRowData(start, result.getList());
				}
				display.enableBtnSearch(true);
			}
			@Override
			protected void callService(AsyncCallback<ResultDTO<CustomerDTO>> cb) {
				rpcCustomerService.getSearchCustomers(pageCursor,pageSize, searchParam,cb);	
			}
		}.retry(3);
}
	
	private void doChangeRange() {
		if(!search){			
			populateCustomersList();
		}else{
			doSearch();
		}	
	}
	
	private void populateCustomersList(){
		search = false;
		final int start = display.getTable().getVisibleRange().getStart();
		pageNum = display.getPage();
		try{
			pageCursor = cursors.get(pageNum);
		}
		catch(Exception e){
			pageCursor = null;
		}
		display.showBusyIndicator();
		new RPCCall<ResultDTO<CustomerDTO>>(){
			@Override
			public void onFailure(Throwable caught) {
				display.hideBusyIndicator();
				Window.alert(CloudMobile.constants.eGetCustomers());
			}
			@Override
			public void onSuccess(ResultDTO<CustomerDTO> result) {
				display.hideBusyIndicator();
				try{
					pageCursor = cursors.get(pageNum+1);
				}
				catch(Exception e){
					pageCursor = null;
				}
				if(result != null){
						if(pageCursor == null)
							cursors.add(result.getCursorString());
						display.getTable().setRowData(start, result.getList());	
				}
			}
			@Override
			protected void callService(AsyncCallback<ResultDTO<CustomerDTO>> cb) {
				rpcCustomerService.getCustomers(pageCursor,pageSize,userA.getName(),cb);		
			}
		}.retry(3);
	}
	@Override
	public void go(HasWidgets container) {
		container.clear();
		container.add(display.asWidget());
	}
	
	private void updateRowCount(){
		new RPCCall<Integer>(){
			@Override
			public void onFailure(Throwable caught) {
				Window.alert(CloudMobile.constants.eGetCountCustomers());
			}
			@Override
			public void onSuccess(Integer result) {
				display.getTable().setRowCount(result,true);
				if(result>0)
					populateCustomersList();	
			}
			@Override
			protected void callService(AsyncCallback<Integer> cb) {
				rpcCustomerService.getCustomersCount(userA.getName(),cb);		
			}
		}.retry(3);	 	
	}
	
	private void updateSRowCount(){
		new RPCCall<Integer>(){
			@Override
			public void onFailure(Throwable caught) {
				Window.alert(CloudMobile.constants.eGetCountCustomers());
			}
			@Override
			public void onSuccess(Integer result) {
				display.getTable().setRowCount(result,true);
				if(result>0){
					doSearch();
				}
				else
					display.enableBtnSearch(true);
					
			}
			@Override
			protected void callService(AsyncCallback<Integer> cb) {
				rpcCustomerService.getSearchedCustomersCount(searchParam,cb);		
			}
		}.retry(3);
	}
		
}
